package com.hsgene.generator.util.generator;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

/**
 * 材料申领编号生成器
 *
 * @author wangbing
 * @version 1.0, 2018/8/13
 */
public class MaterialApplyGenerator extends AbstractGenerator {

    private final static String REDIS_APPLY_PREFIX_KEY = REDIS_PREFIX_KEY + "material_apply:";

    private final static String INFIX_PATTERN = "yyyyMMdd";

    private final static String DEFAULT_PREFIX = "HCSL";

    private final static Integer MAX_SUFFIX = 9999;

    private volatile static MaterialApplyGenerator instance;

    private MaterialApplyGenerator() {
    }

    public static MaterialApplyGenerator getInstance() {
        if (instance == null) {
            synchronized (MaterialApplyGenerator.class) {
                if (instance == null) {
                    instance = new MaterialApplyGenerator();
                }
            }
        }

        return instance;
    }

    @Override
    public String generate(String prefix) {
        return generate(prefix == null ? DEFAULT_PREFIX : prefix, LocalDate.now());
    }

    private String generate(String prefix, LocalDate currentDate) {
        StringBuilder builder = new StringBuilder();
        String infix = currentDate.format(DateTimeFormatter.ofPattern(INFIX_PATTERN));
        String redisKey = REDIS_APPLY_PREFIX_KEY + prefix + infix;
        Integer suffix = getIncrementSuffix(redisKey);

        if (suffix < 0 || suffix > MAX_SUFFIX) {
            // 当前后缀已经超过最大值限制，重新获取新的值
            return generate(prefix, currentDate.plusDays(1));
        }
        // 前缀、中缀、后缀
        builder.append(prefix)
                .append(infix)
                .append(String.format("%04d", suffix));

        return builder.toString();
    }

    /**
     * 获取自增后缀
     *
     * @param key 键
     * @return 后缀值
     */
    @SuppressWarnings("all")
    @Override
    protected synchronized Integer getIncrementSuffix(final String key) {
        SessionCallback<String> sessionCallback = new SessionCallback<String>() {
            @Override
            public String execute(RedisOperations redisOperations) throws DataAccessException {
                String suffix = (String) redisOperations.opsForValue().get(key);
                redisOperations.watch(key);
                redisOperations.multi();
                if (StringUtils.isEmpty(suffix)) {
                    suffix = "1";
                    redisOperations.opsForValue().set(key, suffix, 1L, TimeUnit.DAYS);
                }
                redisOperations.opsForValue().increment(key, 1L);
                redisOperations.exec();
                redisOperations.unwatch();
                return suffix;
            }
        };
        String suffix = stringRedisTemplate.execute(sessionCallback);

        return Integer.valueOf(suffix);
    }
}
